package service

import (
	"encoding/json"
	"gin_gorm_oj/define"
	"gin_gorm_oj/helper"
	"gin_gorm_oj/model"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"log"
	"net/http"
	"strconv"
	"strings"
)

// GetProblemList
// @Tags 公共方法
// @Summary 问题列表
// @Param page query int false "page"
// @Param size query int false "size"
// @Param keyword query string false "keyword"
// @Param category_id query int false "category_id"
// @Success 200 {string} json "{"code":"200","msg","","data":""}"
// @Router /problemList [get]
func GetProblemList(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", define.DefaultPage))
	size, _ := strconv.Atoi(c.DefaultQuery("size", define.DefaultPageSize))
	keyword := c.Query("keyword")
	category_id := c.Query("category_id")
	list := make([]*model.Problem, 0)
	var count int64
	tx := model.GetProblemList(keyword, category_id) //获取题目列表
	// 分页	偏移量
	err := tx.Count(&count).Offset((page - 1) * size).Limit(size).Find(&list).Error
	if err != nil {
		log.Println("GetProblemList err:", err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "success",
		"data": gin.H{
			"list":  list,
			"count": count,
			"page":  page,
			"size":  size,
		},
	})
}

// GetProblemDetail
// @Tags 公共方法
// @Summary 问题详情
// @Param problem_id query int false "problem_id"
// @Success 200 {string} json "{"code":"200","msg","","data":""}"
// @Router /problemDetail [get]
func GetProblemDetail(c *gin.Context) {
	id := c.Query("problem_id")
	if id == "" {
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "problem_id不能为空",
			"data": "",
		})
		return
	}
	problem := new(model.Problem)
	err := model.DB.Where("id=?", id).Preload("ProblemCategories").Preload("ProblemCategories.Category").First(problem).Error
	if err != nil {
		log.Println("GetProblemDetail err:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "获取题目失败",
			"data": "",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "success",
		"data": problem,
	})
}

// CreateProblem
// @Tags 私有方法
// @Summary 创建题目
// @Param authorization header string true "authorization"
// @Param title formData string true "title"
// @Param content formData string true "content"
// @Param max_runtime formData int false "max_runtime"
// @Param max_memory formData int false "max_memory"
// @Param category_ids formData []string false "category_ids" collectionFormat(multi)
// @Param test_cases formData []string true "test_cases" collectionFormat(multi)
// @Success 200 {string} json "{"code":"200","msg","","data":""}"
// @Router /admin/createProblem [post]
func CreateProblem(c *gin.Context) {
	title := c.PostForm("title")
	content := c.PostForm("content")
	max_runtime, _ := strconv.Atoi(c.PostForm("max_runtime"))
	max_memory, _ := strconv.Atoi(c.PostForm("max_memory"))
	category_ids := c.PostFormArray("category_ids")
	test_cases := c.PostFormArray("test_cases")
	if title == "" || content == "" || len(test_cases) == 0 {
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "参数不能为空",
			"data": "",
		})
		return
	}
	// 添加唯一标识
	identity := helper.GetUUID()
	problem := &model.Problem{
		Title:      title,
		Content:    content,
		MaxRuntime: max_runtime,
		MaxMemory:  max_memory,
	}
	problem.Identity = identity
	// 添加题目分类
	problemCategories := make([]*model.ProblemCategory, 0)
	for _, id := range category_ids {
		categoryID, _ := strconv.Atoi(id)
		problemCategories = append(problemCategories, &model.ProblemCategory{
			ProblemID:  problem.ID,
			CategoryID: uint(categoryID),
		})
	}
	problem.ProblemCategories = problemCategories

	//测试用例
	testCases := make([]*model.TestCase, 0)
	for _, testCase := range test_cases {
		//{"input":"1 2\n","output":"3\n"}
		caseMap := make(map[string]string)
		err := json.Unmarshal([]byte(testCase), &caseMap) // 解析测试用例
		if err != nil {
			log.Println("CreateProblem err:", err)
			c.JSON(http.StatusOK, gin.H{
				"code": -1,
				"msg":  "测试用例格式错误",
				"data": "",
			})
			return
		}
		testCases = append(testCases, &model.TestCase{
			ProblemID: problem.ID,
			Identity:  problem.Identity,
			Input:     caseMap["input"],
			Output:    caseMap["output"],
		})
	}
	problem.TestCases = testCases

	err := model.DB.Create(problem).Error
	if err != nil {
		log.Println("CreateProblem err:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "创建题目失败",
			"data": "",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "success",
		"data": map[string]interface{}{
			"identity":     identity,
			"title":        title,
			"content":      content,
			"max_runtime":  strconv.Itoa(max_runtime),
			"max_memory":   strconv.Itoa(max_memory),
			"category_ids": strings.Join(category_ids, ","),
			"test_cases":   strings.Join(test_cases, ","),
		},
	})
}

// UpdateProblem
// @Tags 私有方法
// @Summary 更新题目
// @Param authorization header string true "authorization"
// @Param identity formData string true "identity"
// @Param title formData string true "title"
// @Param content formData string true "content"
// @Param max_runtime formData int false "max_runtime"
// @Param max_memory formData int false "max_memory"
// @Param category_ids formData []string false "category_ids" collectionFormat(multi)
// @Param test_cases formData []string true "test_cases" collectionFormat(multi)
// @Success 200 {string} json "{"code":"200","msg","","data":""}"
// @Router /admin/updateProblem [put]
func UpdateProblem(c *gin.Context) {
	identity := c.PostForm("identity")
	title := c.PostForm("title")
	content := c.PostForm("content")
	maxRuntime, _ := strconv.Atoi(c.PostForm("max_runtime"))
	maxMemory, _ := strconv.Atoi(c.PostForm("max_memory"))
	categoryIds := c.PostFormArray("category_ids")
	testCases := c.PostFormArray("test_cases")
	if identity == "" || title == "" || content == "" || len(testCases) == 0 || len(categoryIds) == 0 || maxRuntime == 0 || maxMemory == 0 {
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "参数不能为空",
			"data": "",
		})
		return
	}
	// 事务处理
	if err := model.DB.Transaction(func(tx *gorm.DB) error {
		//更新题目
		problem := &model.Problem{
			Identity:   identity,
			Title:      title,
			Content:    content,
			MaxRuntime: maxRuntime,
			MaxMemory:  maxMemory,
		}
		err := tx.Where("identity=?", identity).Updates(problem).Error
		if err != nil {
			log.Println("UpdateProblem err:", err)
			return err
		}
		//查询问题
		err = tx.Where("identity=?", identity).Find(problem).Error
		if err != nil {
			log.Println("UpdateFindProblem err:", err)
			return err
		}
		//更新分类
		//删除旧的分类
		err = tx.Where("problem_id=?", problem.ID).Delete(&model.ProblemCategory{}).Error
		if err != nil {
			log.Println("UpdateDeleteProblemCategory err:", err)
			return err
		}
		//添加新的分类
		problemCategories := make([]*model.ProblemCategory, 0)
		for _, id := range categoryIds {
			categoryID, _ := strconv.Atoi(id)
			problemCategories = append(problemCategories, &model.ProblemCategory{
				ProblemID:  problem.ID,
				CategoryID: uint(categoryID),
			})
		}
		err = tx.Create(&problemCategories).Error
		if err != nil {
			log.Println("UpdateCreateProblemCategory err:", err)
			return err
		}
		//更新测试用例
		//删除旧的测试用例
		err = tx.Where("problem_id=?", problem.ID).Delete(&model.TestCase{}).Error
		if err != nil {
			log.Println("UpdateDeleteTestCase err:", err)
			return err
		}
		//添加新的测试用例
		testCaseList := make([]*model.TestCase, 0)
		for _, testCase := range testCases {
			//{"input":"1 2\n","output":"3\n"}
			caseMap := make(map[string]string)
			err := json.Unmarshal([]byte(testCase), &caseMap) // 解析测试用例
			if err != nil {
				log.Println("UpdateProblem json.Unmarshal err:", err)
				return err
			}
			testCaseList = append(testCaseList, &model.TestCase{
				ProblemID: problem.ID,
				Identity:  problem.Identity,
				Input:     caseMap["input"],
				Output:    caseMap["output"],
			})
		}
		err = tx.Create(&testCaseList).Error
		if err != nil {
			log.Println("UpdateCreateTestCase err:", err)
			return err
		}
		return nil
	}); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "问题更新失败" + err.Error(),
			"data": "",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "问题更新成功",
	})
}
